package io.modifier.basic.compose.widget.aowsome

import android.content.res.Configuration
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.Transition
import androidx.compose.animation.core.animateDp
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
import androidx.compose.animation.core.updateTransition
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.RoundRect
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.StrokeJoin
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.drawscope.clipPath
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.lerp
import io.modifier.basic.compose.theme.AppTheme
import java.time.Duration
import java.time.LocalDateTime

private val SleepAwake = Color(0xFFFFEAC1) // 清醒时期
private val SleepRem = Color(0xFFFFDD9A) // 快速动眼睡眠
private val SleepLight = Color(0xFFFFCB66) // 核心睡眠
private val SleepDeep = Color(0xFFFF973C) // 深度睡眠

private enum class SleepType(val title: String) {
    Awake("清醒时期"), // 清醒时期
    REM("快速动眼睡眠"), // 快速动眼睡眠
    Light("核心睡眠时期"), // 核心睡眠时期
    Deep("深度睡眠时期") // 深度睡眠时期
}

@RequiresApi(Build.VERSION_CODES.O)
private data class SleepPeriod(
    // 每日睡眠中的不同睡眠阶段
    val startTime: LocalDateTime,
    val endTime: LocalDateTime,
    val type: SleepType,
) {

    val duration: Duration by lazy {
        Duration.between(startTime, endTime)
    }
}

@RequiresApi(Build.VERSION_CODES.O)
private data class SleepDayData(
    // 每日睡眠数据
    val startDate: LocalDateTime,
    val sleepPeriods: List<SleepPeriod>,
    val sleepScore: Int,
) {
    val firstSleepStart: LocalDateTime by lazy {
        sleepPeriods.sortedBy(SleepPeriod::startTime).first().startTime
    }
    val lastSleepEnd: LocalDateTime by lazy {
        sleepPeriods.sortedBy(SleepPeriod::startTime).last().endTime
    }
    val totalTimeInBed: Duration by lazy {
        Duration.between(firstSleepStart, lastSleepEnd)
    }
}

@RequiresApi(Build.VERSION_CODES.O)
private data class SleepGraphData(
    val sleepDayData: List<SleepDayData>,
) {
    val earliestStartHour: Int by lazy {
        sleepDayData.minOf { it.firstSleepStart.hour }
    }
    val latestEndHour: Int by lazy {
        sleepDayData.maxOf { it.lastSleepEnd.hour }
    }
}

@RequiresApi(Build.VERSION_CODES.O)
private val sleepData = SleepGraphData(
    listOf(
        SleepDayData(
            LocalDateTime.now().minusDays(7),
            listOf(
                SleepPeriod(
                    startTime = LocalDateTime.now()
                        .minusDays(7)
                        .withHour(21)
                        .withMinute(8),
                    endTime = LocalDateTime.now()
                        .minusDays(7)
                        .withHour(21)
                        .withMinute(40),
                    type = SleepType.Awake
                ),
                SleepPeriod(
                    startTime = LocalDateTime.now()
                        .minusDays(7)
                        .withHour(21)
                        .withMinute(40),
                    endTime = LocalDateTime.now()
                        .minusDays(7)
                        .withHour(22)
                        .withMinute(20),
                    type = SleepType.Light
                ),
                SleepPeriod(
                    startTime = LocalDateTime.now()
                        .minusDays(7)
                        .withHour(22)
                        .withMinute(20),
                    endTime = LocalDateTime.now()
                        .minusDays(7)
                        .withHour(22)
                        .withMinute(50),
                    type = SleepType.Deep
                ),
                SleepPeriod(
                    startTime = LocalDateTime.now()
                        .minusDays(7)
                        .withHour(22)
                        .withMinute(50),
                    endTime = LocalDateTime.now()
                        .minusDays(7)
                        .withHour(23)
                        .withMinute(30),
                    type = SleepType.REM
                ),
                SleepPeriod(
                    startTime = LocalDateTime.now()
                        .minusDays(7)
                        .withHour(23)
                        .withMinute(30),
                    endTime = LocalDateTime.now()
                        .minusDays(6)
                        .withHour(1)
                        .withMinute(10),
                    type = SleepType.Deep
                ),
                SleepPeriod(
                    startTime = LocalDateTime.now()
                        .minusDays(6)
                        .withHour(1)
                        .withMinute(10),
                    endTime = LocalDateTime.now()
                        .minusDays(6)
                        .withHour(2)
                        .withMinute(30),
                    type = SleepType.Awake
                ),
                SleepPeriod(
                    startTime = LocalDateTime.now()
                        .minusDays(6)
                        .withHour(2)
                        .withMinute(30),
                    endTime = LocalDateTime.now()
                        .minusDays(6)
                        .withHour(4)
                        .withMinute(10),
                    type = SleepType.Deep
                ),
                SleepPeriod(
                    startTime = LocalDateTime.now()
                        .minusDays(6)
                        .withHour(4)
                        .withMinute(10),
                    endTime = LocalDateTime.now()
                        .minusDays(6)
                        .withHour(5)
                        .withMinute(30),
                    type = SleepType.Awake
                )
            ),
            sleepScore = 90
        ),
    )
)

private const val animationDuration = 500
private val barHeight = 24.dp //每个睡眠阶段矩形的高度

@RequiresApi(Build.VERSION_CODES.O)
@Composable
private fun SleepRoundedBar(
    sleepDayData: SleepDayData,
    transition: Transition<Boolean>
) {
    val animateHeight by transition.animateDp(
        label = "height",
        transitionSpec = {
            spring(
                dampingRatio = Spring.DampingRatioLowBouncy,
                stiffness = Spring.StiffnessLow
            )
        }
    ) { isExpanded ->
        if (isExpanded) 100.dp else 24.dp
    }

    val animationProgress by transition.animateFloat(
        label = "progress",
        transitionSpec = {
            spring(
                dampingRatio = Spring.DampingRatioLowBouncy,
                stiffness = Spring.StiffnessLow
            )
        }) { isExpanded ->
        if (isExpanded) 1f else 0f
    }

    Spacer(modifier = Modifier
        .drawWithCache {
            val barHeightPx = barHeight.toPx()
            val sleepGraphPath = Path()
            val stroke = Stroke(
                width = 2.dp.toPx(),
                cap = StrokeCap.Round,
                join = StrokeJoin.Round
            )
            val sleepGradientBarColorStops = arrayOf(
                0f to SleepAwake,
                0.33f to SleepRem,
                0.66f to SleepLight,
                1f to SleepDeep
            )
            val gradientBrush = Brush.verticalGradient(
                colorStops = sleepGradientBarColorStops,
                startY = 0f,
                endY = SleepType.entries.size * barHeightPx
            )

            sleepDayData.sleepPeriods.forEach { period ->
                // 添加代表每个睡眠阶段的矩形
                val percentageOfTotal = period.duration
                    .toMinutes()
                    .toFloat() / sleepDayData.totalTimeInBed
                    .toMinutes()
                    .toFloat()
                val periodWidth = percentageOfTotal * this.size.width

                // 计算初始坐标
                val offsetStartX =
                    Duration
                        .between(sleepDayData.firstSleepStart, period.startTime)
                        .toMinutes()
                        .toFloat() /
                            sleepDayData.totalTimeInBed
                                .toMinutes()
                                .toFloat() *
                            this.size.width
                val heightBySleepType = when (period.type) {
                    SleepType.Awake -> 0f
                    SleepType.REM -> barHeightPx
                    SleepType.Light -> barHeightPx * 2
                    SleepType.Deep -> barHeightPx * 3
                }
                val offsetStartY = lerp(
                    0f,
                    heightBySleepType,
                    animationProgress
                )

                sleepGraphPath.lineTo(offsetStartX, offsetStartY + barHeightPx / 2)
                sleepGraphPath.addRect(
                    Rect(
                        offset = Offset(offsetStartX, offsetStartY),
                        size = Size(periodWidth, barHeightPx)
                    )
                )
                sleepGraphPath.moveTo(
                    offsetStartX + periodWidth,
                    offsetStartY + barHeightPx / 2
                )
            }
            val animateCornerRadius = CornerRadius(
                lerp(
                    10.dp.toPx(),
                    2.dp.toPx(),
                    animationProgress
                )
            )
            val roundCornerPath = Path()
            roundCornerPath.addRoundRect(
                RoundRect(
                    Rect(
                        Offset(0f, 0f),
                        Size(this.size.width, this.size.height)
                    ),
                    animateCornerRadius
                )
            )
            onDrawBehind {
                clipPath(roundCornerPath) {
                    drawPath(sleepGraphPath, gradientBrush)
                    drawPath(sleepGraphPath, gradientBrush, style = stroke)
                }
            }
        }
        .height(animateHeight)
        .fillMaxWidth()
    )
}


@RequiresApi(Build.VERSION_CODES.O)
@OptIn(ExperimentalAnimationApi::class)
@Composable
private fun MainPage(modifier: Modifier = Modifier) {
    var isExpanded by remember { mutableStateOf(false) }
    val transition = updateTransition(targetState = isExpanded, label = "expanded")

    Column(
        modifier = Modifier
            .clickable(indication = null,
                interactionSource = remember { MutableInteractionSource() }
            ) {
                isExpanded = !isExpanded
            }
            .fillMaxSize()
            .padding(16.dp),
    ) {
        Spacer(modifier = Modifier.height(100.dp))
        transition.AnimatedVisibility(
            enter = fadeIn(animationSpec = tween(animationDuration)) + expandVertically(
                animationSpec = tween(animationDuration)
            ),
            exit = fadeOut(animationSpec = tween(animationDuration)) + shrinkVertically(
                animationSpec = tween(animationDuration)
            ),
            content = { },
            visible = { it }
        )
        SleepRoundedBar(sleepData.sleepDayData.first(), transition)
    }
}

@Composable
private fun PreviewLine2() {
    AppTheme {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            MainPage()
        }
    }
}

@Preview(backgroundColor = 0xFF121212, showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO)
@Composable
private fun PreviewLightLine2() {
    PreviewLine2()
}

@Preview(backgroundColor = 0xFFf5f5f5, showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
private fun PreviewDarkLine2() {
    PreviewLine2()
}